﻿// -----------------------------------------------------------------------
// <copyright company="Christoph van der Fecht - VDsoft">
// Copyright (C) Christoph van der Fecht - VDsoft - All Rights Reserved
// Unauthorized copying of this file, via any medium is strictly prohibited,
// unless it is communicated and authorized by the copyright owner.
// </copyright>
// -----------------------------------------------------------------------

namespace SeriesManager.Model
{
	using System;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.ComponentModel;
	using System.Linq;
	using System.Linq.Expressions;
	using System.Text;
	using System.Threading.Tasks;


	/// <summary>
	/// Series with all episodes of the series.
	/// </summary>
	public class Series : INotifyPropertyChanged
	{
		/// <summary>
		/// The Name.
		/// </summary>
		private string name = string.Empty;

		/// <summary>
		/// The Seasons.
		/// </summary>
		private ObservableCollection<Season> seasons = new ObservableCollection<Season>();

		/// <summary>
		/// The BannerPath.
		/// </summary>
		private string bannerPath;

		/// <summary>
		/// Initializes a new instance of the <see cref="Series"/> class.
		/// </summary>
		public Series()
		{

		}

		/// <summary>
		/// Gets or sets the Name property.
		/// </summary>
		public string Name
		{
			get
			{
				return this.name;
			}

			set
			{
				if (value == this.name)
				{
					return;
				}

				this.name = value;
				this.RaiseProperyChanged(this.Getname(x => x.Name));
			}
		}

		/// <summary>
		/// Gets or sets the Seasons property.
		/// </summary>
		public ObservableCollection<Season> Seasons
		{
			get
			{
				return this.seasons;
			}

			set
			{
				if (value == this.seasons)
				{
					return;
				}

				this.seasons = value;
				this.RaiseProperyChanged(this.Getname(x => x.Seasons));
			}
		}

		/// <summary>
		/// Gets or sets the BannerPath property.
		/// </summary>
		public string BannerPath
		{
			get
			{
				return this.bannerPath;
			}

			set
			{
				if (value == this.bannerPath)
				{
					return;
				}

				this.bannerPath = value;
				this.RaiseProperyChanged(this.Getname(x => x.BannerPath));
			}
		}

		/// <summary>
		/// Occurs when a property changed its value.
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>
		/// Converts a <see cref="TVDB.Model.Series"/> into a <see cref="Series"/>.
		/// </summary>
		/// <param name="toConvert"><see cref="TVDB.Model.Series"/> to convert.</param>
		/// <returns>The <see cref="Series"/> with all seasons and episodes.</returns>
		public static explicit operator Series(TVDB.Model.Series toConvert)
		{
			if (toConvert == null)
			{
				return null;
			}

			Series converted = new Series()
			{
				Name = toConvert.Name,
				BannerPath = toConvert.Banner
			};

			List<Season> seasons = new List<Season>();

			foreach (TVDB.Model.Episode currentEpisode in toConvert.Episodes)
			{
				Season belonging = seasons.SingleOrDefault(x => x.Number == currentEpisode.SeasonNumber);

				if (belonging == null)
				{
					belonging = new Season(converted, currentEpisode.SeasonNumber);
					seasons.Add(belonging);
				}

				Episode toAdd = (Episode)currentEpisode;
				toAdd.Season = belonging;
				belonging.AddEpisode(toAdd);
			}

			converted.Seasons = new ObservableCollection<Season>(seasons);

			return converted;
		}

		/// <summary>
		/// Adds a season to the collection.
		/// </summary>
		/// <param name="toAdd">Season to add.</param>
		public void AddSeason(Season toAdd)
		{
			if (toAdd == null)
			{
				throw new ArgumentNullException("toAdd", "Season to add must not be null");
			}

			this.Seasons.Add(toAdd);
		}
		
		/// <summary>
		/// Get the name of the provided property.
		/// </summary>
		/// <typeparam name="T">Object that contains the changed property.</typeparam>
		/// <param name="selector">Selector for the property.</param>
		/// <returns>Name of the property.</returns>
		private string Getname<T>(Expression<Func<Series, T>> selector)
		{
			var body = (MemberExpression)selector.Body;
			return body.Member.Name;
		}

		/// <summary>
		/// Raises the <see cref="PropertyChanged"/> event.
		/// </summary>
		/// <param name="propertyName">Name of the property that changed its value.</param>
		private void RaiseProperyChanged(string propertyName)
		{
			if (this.PropertyChanged != null)
			{
				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
	}
}
